# -*- coding: utf-8 -*-

import sys
import shutil
import os
import gettext
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.settings import Settings
from kivy.utils import platform
from kivy.logger import Logger
from kivy.uix.popup import Popup

import model
from model.gamestate import Phase
from model.syssettings import SysSettings
from model.dictionary import Dictionary

from ui.welcome_screen import WelcomeScreen
from ui.add_player import AddPlayerScreen
from ui.add_words import AddWords
from ui.players_order import PlayersOrderWidget
from ui.from_to import FromToWidget
from ui.start_game import StartGame
from ui.guess_word import GuessWordScreen
from ui.presenter import Presenter
from ui.results_of_one_pair import ResultsOfOnePair
from ui.game_config import GameConfig
from ui.game_results import GameResults
from ui.before_round_screen import BeforeRoundScreen
from ui.quick_game_settings import QuickGameSettings
from ui.rules import RulesScreen
from ui.cur_result import CurResults
from ui.load_game import LoadGameScreen
from ui.edit_players import EditPlayers
from ui.join import Join
from ui.about import AboutScreen
from ui.next_round import NextRound
from ui.hat_widget import open_ok_popup

from constants import PATH, LOCALE_PATH, CONFIG_FILE, CONFIG_TEMPLATE_FILE,\
    ICON, LOCALE, PICKLED_GAMESTATE, STATISTICS_FOLDER


gettext.bindtextdomain('thehat', LOCALE_PATH)


def update_config():
    """ Checks the config file's version and updates it from template

        Checks the config file's version in the first line and, if it is out
        of date, replaces the config with the config template
    """
    with open(CONFIG_FILE, 'r') as config:
        conf_ver = config.readline()
        Logger.debug('config version is %s' % (conf_ver))
    with open(CONFIG_TEMPLATE_FILE, 'r') as template:
        temp_ver = template.readline()
        Logger.debug('config template version is %s' % (temp_ver))
    if conf_ver < temp_ver:
        shutil.copyfile(CONFIG_TEMPLATE_FILE, CONFIG_FILE)
        Logger.debug('config is out of date. replacing it with template')


class MainView(Widget):
    pass


class MainViewApp(App):
    title = 'The Hat'
    icon = ICON

    def build(self):
        """ Creates app window

            Creates main_view widget, presenter widget, settings, sets screen
            orientation and binds keyboard listening
        """
        self.config = None
        self.create_config()
        locale = self.config.getdefault('Language', 'lang', LOCALE)
        self.set_locale(locale)
        self.main_view = MainView()
        self.presenter = Presenter(self.main_view, PATH)
        self.register_views()

        self.use_kivy_settings = False
        self.create_game_state_settings()

        self.curr_orientation = Window.rotation
        self.prev_orientation = Window.rotation

        self.main_view.bind(on_keyboard=self.handle_keyboard)
        self.update_confirmation_button_time()
        self.presenter.change_phase(Phase.WELCOME)
        return self.main_view

    def update_confirmation_button_time(self):
        from ui.confirmation_button import ConfirmationButton
        ConfirmationButton.time =\
            self.presenter.settings.game.confirmation_time_sec

    def set_locale(self, locale):
        try:
            lang = gettext.translation(domain='thehat', localedir=LOCALE_PATH,
                                       languages=[locale], codeset='utf-8')
            lang.install(True)
            Logger.debug('main.py: set_locale(): locale ' + locale +
                         ' sucessfully installed')
        except:
            Logger.warn('main.py: set_locale(): unknown locale %s'
                        % locale)
            Logger.warn('main.py: set_locale(): using default locale %s'
                        % LOCALE)
            self.set_locale(LOCALE)

    def register_views(self):
        """ Adds all screens to presenter
        """
        views = [
            (Phase.WELCOME, WelcomeScreen, ['welcomescreen']),
            (Phase.START_GAME, StartGame, ['startgame']),
            (Phase.GUESS_WORD, GuessWordScreen, ['guesswordscreen']),
            (Phase.ADD_PLAYER, AddPlayerScreen, ['addplayer']),
            (Phase.ADD_WORDS, AddWords, ['addwords']),
            (Phase.FROM_TO, FromToWidget, ['fromto']),
            (Phase.PLAYERS_ORDER, PlayersOrderWidget, ['playersorder']),
            (Phase.RESULTS_OF_ONE_PAIR, ResultsOfOnePair,
                ['resultsofonepair']),
            (Phase.GAME_CONFIG, GameConfig, ['gameconfig']),
            (Phase.BEFORE_ROUND, BeforeRoundScreen, ['beforeroundscreen']),
            (Phase.GAME_RESULTS, GameResults, ['gameresults']),
            (Phase.QUICK_GAME_SETTINGS, QuickGameSettings,
                ['quickgamesettings']),
            (Phase.RULES, RulesScreen, ['rules']),
            (Phase.CURRES, CurResults, ['curresults']),
            (Phase.LOAD_GAME, LoadGameScreen, ['loadgame']),
            (Phase.JOIN, Join, ['join']),
            (Phase.EDIT_PLAYERS, EditPlayers, ['editplayers']),
            (Phase.ABOUT, AboutScreen, ['about']),
            (Phase.NEXT_ROUND, NextRound, ['nextround'])]

        for view in views:
            self.presenter.register_view(*view)

    def create_game_state_settings(self):
        """ Creates rpesenter.game_state if they do not exist
        """
        if (not hasattr(self.presenter.game_state, 'settings') or
                self.presenter.game_state.settings is None):
            self.presenter.game_state.settings = model.gamestate.Settings()

    def create_config(self):
        """ Loads and parses configuration file
        """
        if self.config is None:
            self.load_config()
            self.config.read(CONFIG_FILE)
            Logger.debug('Loading config from '+CONFIG_FILE)

    def build_settings_menu(self):
        """ Assembles settings screen from settings panels
        """
        curr_phase = self.presenter.game_state.phase
        settings = self._app_settings

        if curr_phase == Phase.GUESS_WORD:
            return False
        if settings is not None and hasattr(settings, 'phase') and\
                settings.phase == curr_phase:
            self._app_settings = settings
            return True

        self._app_settings = None
        settings = super(MainViewApp, self)._create_settings()
        settings.phase = curr_phase

        panels = []
        panels.append((_('Interface settings'), PATH+'/ui/gameconfig.json'))
        panels.append((_('Sound settings'), PATH+'/ui/soundconfig.json'))

        select_dictionaries = False
        if curr_phase == Phase.WELCOME:
            panels.append((_('Quick game settings'),
                          PATH+'/ui/defquickgameconfig.json'))
            panels.append((_('Game settings'),
                          PATH+'/ui/defgameconfig.json'))
            select_dictionaries = True

        for panel in panels:
            settings.add_json_panel(panel[0], self.config, panel[1])

        if select_dictionaries:
            settings.add_json_panel(_('Dictionaries settings'), self.config,
                                    data=str(Dictionary.make_json()))

        self._app_settings = settings
        return True

    def rotate_horizontally(self):
        """ Changes window rotation to horizontal
        """
        horizontal_orientation =\
            self.presenter.settings.graphics.horizontal_orientation
        self.presenter.set_orientation(horizontal_orientation)

    def rotate_vertically(self):
        """ Changes window rotation to vertical
        """
        vertical_orientation =\
            self.presenter.settings.graphics.vertical_orientation
        self.presenter.set_orientation(vertical_orientation)

    def open_settings(self, *largs):
        """ Called when settings button is pressed and settings are to open
        """
        self.rotate_horizontally()
        ret = self.build_settings_menu()
        return (ret and super(MainViewApp, self).open_settings(*largs))

    def close_settings(self, *largs):
        """ Called when settings button is pressed and settings are to close
        """
        self.presenter.rotate()
        self.presenter.update()
        return super(MainViewApp, self).close_settings(*largs)

    def reload_screen(self):
        self.presenter.change_phase(self.presenter.game_state.phase)
        self.rotate_horizontally()

    def on_config_change(self, config, section, key, value):
        """ Called when settings change on settings screen
        """
        self.config.write()
        attr = (section, key)

        if attr == ('Language', 'lang'):
            Logger.debug('main.py: on_config_change(): set lang to %s'
                         % value)

            self.set_locale(value)
            self.reload_screen()
            return

        self.presenter.settings.set_property(section, key, value)

        if section == 'Dictionaries Defaults':
            self.reload_screen()

        if section == 'Graphics':
            orientation =\
                self.presenter.settings.graphics.horizontal_orientation
            self.presenter.set_orientation(orientation)

        self.update_confirmation_button_time()
        self.reload_screen()

    def on_pause(self):
        """ Called when application is going to be paused
        """
        return self.presenter.close_app()

    def on_stop(self):
        """ Called when application is going to be closed
        """
        if hasattr(self, 'presenter'):
            return self.presenter.close_app()

    def handle_keyboard(self, window, key, *largs):
        """ Handles keyboard
        """
        if self.presenter.game_state.phase == Phase.GUESS_WORD:
            pass
        if (key == 27 or key == 1001):
            if self.presenter.game_state.phase == Phase.WELCOME:
                Logger.debug('Key %s was pressed. Passing to default handler.'
                             % key)
            return False
            self.main_view.content.children[0].go_back()
            return True
        if key == 1002:
            if self.presenter.game_state.phase == Phase.WELCOME:
                Logger.debug('Key %s was pressed. Pausing.' % key)
                on_pause()
            else:
                Logger.debug('Key %s was pressed. Heading to welcome screen'
                             % key)
                self.presenter.change_phase(Phase.WELCOME)
            return True

    def on_start(self):
        """ Called when application is going to be resumed

            Remaps hardware keys and resumes application
        """
        if platform() == 'android':
            import android

            android.map_key(android.KEYCODE_BACK, 1001)
            android.map_key(android.KEYCODE_HOME, 1002)

        self._app_window.bind(on_keyboard=self.handle_keyboard)
        self.presenter.resume_app()


def run_app():
    if not os.path.exists(CONFIG_FILE):
        Logger.warn('No config found')
        if not os.path.exists(CONFIG_TEMPLATE_FILE):
            raise Exception('No config files found')
        else:
            shutil.copyfile(CONFIG_TEMPLATE_FILE, CONFIG_FILE)

    if os.path.exists(CONFIG_FILE) and\
            os.path.exists(CONFIG_TEMPLATE_FILE):
        update_config()

    if not os.path.exists(STATISTICS_FOLDER):
        os.mkdir(STATISTICS_FOLDER)

    main_view_app = MainViewApp()
    if 'nocatch' in sys.argv:
        main_view_app.run()
    else:
        try:
            main_view_app.run()
        except Exception as msg:
            main_view_app.on_stop()
            import traceback
            if os.path.exists(PICKLED_GAMESTATE):
                import datetime
                Logger.debug('moving pickled gamestate after crash')
                now = datetime.datetime.now()
                time_stamp = now.strftime('%m.%d_%H.%M.%S')
                shutil.copyfile(PICKLED_GAMESTATE,
                                PICKLED_GAMESTATE+'.'+time_stamp)
                os.remove(PICKLED_GAMESTATE)
            if os.path.exists(CONFIG_FILE):
                os.remove(CONFIG_FILE)
            traceback.print_exc()
            raise msg


if __name__ == "__main__":
    run_app()
